; ReadSector(LPVOID lpDstBuf, DWORD dwLBA)
%ifndef ReadSector_asm
%define ReadSector_asm

%include "FileSystem/ATADisk.S"
%define dwLBA dword [ebp + 12]
%define lpDstBuf dword [ebp + 8]
%define dwRetryTimes dword [ebp - 4]

%define MAX_RETRY_TIMES (9)
%define READ_OPERATION (0x20)
bits 32
global ReadSector
ReadSector:
ReadSector.Initialize:
    push ebp
    mov ebp, esp
    push dword MAX_RETRY_TIMES ; dwRetryTimes = MAX_RETRY_TIMES
    ; 读入 1 个扇区
    mov edx, rSectCnt
    mov eax, 1
    out dx, al
    ; 存入 LBA 0~7 位地址
    mov eax, dwLBA
    mov edx, rSectN_LBAlo
    out dx, al
    ; 存入 LBA 8 ~ 15 位地址
    shr eax, 8
    mov edx, rCylo_LBAmid
    out dx, al
    ; 存入 LBA 16 ~ 23 位地址
    shr eax, 8
    mov edx, rCyhi_LBAhi
    out dx, al
    ; 存入 LBA 24 ~ 27 位地址
    shr eax, 8
    mov edx, rDrv_Head
    or al, 0b1110_0000 ; rDrv_Head 设置为 LBA 模式，使用 Primary Disk，因此高四位为 1110
    out dx, al
    cmp dwRetryTimes, 0
    ; 写入读命令
    je ReadSector.Fail ; 次数耗尽，出错
    dec dwRetryTimes
    mov edx, rStatus_Cmd
    mov al, READ_OPERATION
    out dx, al
ReadSector.Check:
    ; dx 保存的端口用于获取磁盘状态
    mov edx, rAltStatus_DevCtrl
    in al, dx
    test al, 0b0010_0001 ; error
    jnz ReadSector.Initialize ; retry
    test al, 0b1000_0000 ; busy
    jnz ReadSector.Check ; keep checking until data ready
    test al, 0b0000_1000 ; data ready
    jnz ReadSector.ReadData
ReadSector.ReadData:
    push ecx
    push edi
    mov edx, rData ; 数据端口
    mov ecx, 256 ; 256 words
    mov edi, lpDstBuf
    rep insw ; gulp data
    pop edi
    pop ecx
ReadSector.Return:
    add esp, 4
    mov esp, ebp
    pop ebp
    ret
ReadSector.Fail:
    stc ; 有进位表示出错
    jmp ReadSector.Return
%undef dwLBA
%undef lpDstBuf
%undef dwRetryTimes
%undef MAX_RETRY_TIMES
%undef READ_OPERATION
%endif ; ReadSector_asm